/*
Copyright 2010-2011 CumulusCloud
http://cumuluscloud.cc

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cumulusCloud.repository.xml;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import cumulusCloud.common.InformationPath;
import cumulusCloud.common.objects.CloudConfiguration;
import cumulusCloud.repository.ConfigurationRepository;
import cumulusCloud.tools.XML;


public class ConfigurationRepositoryXml implements ConfigurationRepository {
	private static Logger logger = java.util.logging.Logger.getLogger(ConfigurationRepositoryXml.class.getName());
	private String serverFile;
	private String configFile;
	
	public ConfigurationRepositoryXml(String serverFile, String configFile) {
		this.serverFile = serverFile;
		this.configFile = configFile;
		createKeystoreIfNotExists();
	}
	
	private void createKeystoreIfNotExists() {
		if (!(new File(InformationPath.getCloudGlobalConfigPath() + "keystore")).exists()) {
			logger.info("Creating the keystore");
			String command = InformationPath.getJavaBinPath() + "keytool -genkey -alias tomcat -keyalg RSA -keystore \"" + InformationPath.getCloudGlobalConfigPath() + "keystore\"";
			try {
				Process proc = Runtime.getRuntime().exec(command);
				PrintWriter pw = new PrintWriter(proc.getOutputStream());
				
				pw.println("changeit");
				pw.println("changeit");
				pw.println("Cloud");
				pw.println("Cloud");
				pw.println("Cloud");
				pw.println("local");
				pw.println("local");
				pw.println("CA");
				pw.println("yes");
				pw.println();
				pw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	@Override
	public CloudConfiguration load() {
		logger.fine("The ConfigurationRepository is being loaded");
		
		CloudConfiguration result = new CloudConfiguration();
		
		// server.xml
		logger.fine("Loading server.xml");
		try {
			Document doc = XML.loadFromFile(serverFile);
			Element rootElement = doc.getDocumentElement();
			
			NodeList connectorList = ((Element) rootElement.getElementsByTagName("Service").item(0)).getElementsByTagName("Connector");
			for (int i = 0; (connectorList != null) && i < connectorList.getLength(); ++i)  {
				Element nextConnector = (Element) connectorList.item(i);
				String portAttribute = nextConnector.getAttribute("port");
				String sslAttribute = nextConnector.getAttribute("SSLEnabled");
				if ( (sslAttribute != null) && (sslAttribute.equals("true")) ) {
					result.httpsPort = Integer.parseInt(portAttribute);
				} else {
					result.httpPort = Integer.parseInt(portAttribute);
				}
			}
		} catch (Exception e) {
			logger.severe("Could not load the configuration from the file");
			e.printStackTrace();
		}
		
		// config.xml
		logger.fine("Loading config.xml");
		if (new File(configFile).exists()) {
			try {
				Document doc = XML.loadFromFile(configFile);
				Element rootElement = doc.getDocumentElement();

				result.hostName = XML.getTextValue(rootElement, "hostName");
				String value;
				
				value = XML.getTextValue(rootElement, "hostName");
				if (value != null) {
					result.hostName = value;
				}
				
				value = XML.getTextValue(rootElement, "language");
				if (value != null) {
					result.language = value;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		return result;
	}
	
	@Override
	public boolean save(CloudConfiguration newConfig) {
		logger.fine("The ConfigurationRepository is being saved");
		
		// server.xml
		try {
			logger.fine("Saving server.xml");
			Document doc = XML.createXmlDocument();
			
			Element rootElement = doc.createElement("Server");
			rootElement.setAttribute("port", "9005");
			rootElement.setAttribute("shutdown", "SHUTDOWN");
			doc.appendChild(rootElement);
			
			Element listenerElement = doc.createElement("Listener");
			listenerElement.setAttribute("className", "org.apache.catalina.core.AprLifecycleListener");
			listenerElement.setAttribute("SSLEngine", "on");
			rootElement.appendChild(listenerElement);
			listenerElement = doc.createElement("Listener");
			listenerElement.setAttribute("className", "org.apache.catalina.core.JasperListener");
			rootElement.appendChild(listenerElement);
			listenerElement = doc.createElement("Listener");
			listenerElement.setAttribute("className", "org.apache.catalina.mbeans.ServerLifecycleListener");
			rootElement.appendChild(listenerElement);
			listenerElement = doc.createElement("Listener");
			listenerElement.setAttribute("className", "org.apache.catalina.mbeans.GlobalResourcesLifecycleListener");
			rootElement.appendChild(listenerElement);
			
			Element serviceElement = doc.createElement("Service");
			serviceElement.setAttribute("name", "Catalina");
			rootElement.appendChild(serviceElement);
			
			Element connectorElement;
			if (newConfig.httpPort > 0) {
				connectorElement = doc.createElement("Connector");
				connectorElement.setAttribute("port", Integer.toString(newConfig.httpPort));
				connectorElement.setAttribute("protocol", "HTTP/1.1");
				connectorElement.setAttribute("connectionTimeout", "20000");
				if (newConfig.httpsPort > 0) connectorElement.setAttribute("redirectPort", Integer.toString(newConfig.httpsPort));
				serviceElement.appendChild(connectorElement);
			}

			if ( (newConfig.httpsPort > 0) && (new File(InformationPath.getCloudGlobalConfigPath() + "keystore")).exists()) {
				connectorElement = doc.createElement("Connector");
				connectorElement.setAttribute("port", Integer.toString(newConfig.httpsPort));
				connectorElement.setAttribute("protocol", "HTTP/1.1");
				connectorElement.setAttribute("SSLEnabled", "true");
				connectorElement.setAttribute("maxThreads", "150");
				connectorElement.setAttribute("scheme", "https");
				connectorElement.setAttribute("secure", "true");
				connectorElement.setAttribute("clientAuth", "false");
				connectorElement.setAttribute("sslProtocol", "TLS");
				connectorElement.setAttribute("keystoreFile", "${catalina.base}/cloud/config/keystore");
				serviceElement.appendChild(connectorElement);
			}

			Element engineElement = doc.createElement("Engine");
			engineElement.setAttribute("name", "Catalina");
			engineElement.setAttribute("defaultHost", "localhost");
			serviceElement.appendChild(engineElement);
			
			Element hostElement = doc.createElement("Host");
			hostElement.setAttribute("name", "localhost");
			hostElement.setAttribute("appBase", "webapps");
			hostElement.setAttribute("unpackWARs", "true");
			hostElement.setAttribute("autoDeploy", "true");
			hostElement.setAttribute("xmlValidation", "false");
			hostElement.setAttribute("xmlNamespaceAware", "false");
			engineElement.appendChild(hostElement);
			
			XML.saveToFile(doc, serverFile);
		} catch (Exception e) {
			logger.severe("Could not save the ConfigurationRepository");
			e.printStackTrace();
			return false;
		}

		// config.xml
		try {
			logger.fine("Saving config.xml");
			Document doc = XML.createXmlDocument();
			
			Element rootElement = doc.createElement("config");
			doc.appendChild(rootElement);

			Element hostnameElement = doc.createElement("hostName");
			hostnameElement.appendChild(doc.createTextNode( (newConfig.hostName!=null)?newConfig.hostName:"" ));
			rootElement.appendChild(hostnameElement);
			
			Element languageElement = doc.createElement("language");
			languageElement.appendChild(doc.createTextNode(newConfig.language));
			rootElement.appendChild(languageElement);
			
			XML.saveToFile(doc, configFile);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
}
